package yxy.cherry.data.actdata;

import org.redisson.api.RMap;
import yxy.apple.util.ReflectionUtility;
import yxy.apple.util.redisson.RedisConnection;
import yxy.cherry.data.DataCenter;
import yxy.cherry.data.bean.model.DataClass;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;


public class DataCenterAct {

	static private DataCenterAct instance;
	static private String version = "v1.0.0.0";

	public static DataCenterAct getInstance() {
		return instance;
	}

	static public void init(RedisConnection connection, boolean cache, ArrayList<Integer> areaids) {
		System.out.println("*********************活动数据初始化 开始***********************");
		if (instance == null) {
			instance = new DataCenterAct();
			instance.connection = connection;
			instance.cache = cache;
			if (cache) {
				instance.init(areaids);
			}
		}
		System.out.println("*********************活动数据初始化 完成***********************");
	}

	//gm后台调用
	static public void initForGM(RedisConnection connection, boolean cache) {
		System.out.println("*********************活动数据初始化 开始***********************");
		if (instance == null) {
			instance = new DataCenterAct();
			instance.connection = connection;
			instance.cache = cache;
		}
		System.out.println("*********************活动数据初始化 完成***********************");
	}

	private RedisConnection connection;
	private boolean cache;// 缓存功能开关

	private DataCenterAct() {
	}

	private void init(ArrayList<Integer> areaids) {														
//		Set<Class<? extends DataClass>> dataTypeSet = ReflectionUtility.getSubTypesOf("yxy.game.pm2.active.data.bean", DataClass.class);
		Set<Class<? extends DataClass>> dataTypeSet = ReflectionUtility.getSubTypesOf("yxy.cherry.data.bean", DataClass.class);
	
		//加载默认活动数据
		for (Class<? extends DataClass> clazz : dataTypeSet) {
			String name = clazz.getSimpleName();
			if(!name.contains("act")) {
				continue;
			}
			initDefaultData(version, clazz);
		}
		
		//按区加载活动数据
//		Collection<AreaBean> abs = AreaBean.all();
		for(int areaid : areaids) {
//			int areaid = ab.getAreaId();
			for (Class<? extends DataClass> clazz : dataTypeSet) {
				String name = clazz.getSimpleName();
				if(!name.contains("act")) {
					continue;
				}
				initAreaData(version, clazz, areaid);
			}
		}
		
		intMd5Data(areaids);
	}

	synchronized static public <T> T getData(int id, Class<T> clazz, int areaid) {
		return getData(version, String.valueOf(id), clazz, areaid);
	}

	synchronized static public <T> T getData(String code, Class<T> clazz, int areaid) {
		return getData(version, code, clazz, areaid);
	}

	synchronized static public <T> T getData(String version, String code, Class<T> clazz, int areaid) {
		try {
			return instance._getData(version, code, clazz, areaid);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	synchronized static public <T> Map<String, T> getAllData(Class<T> clazz, int areaid) {
		return instance._getAllData(version, clazz, areaid);
	}

	private <T> T _getData(String version, String code, Class<T> clazz, int areaid) throws Exception {
		return _getAllData(version, clazz, areaid).get(code);
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private <T> Map<String, T> _getAllData(String version, Class<T> clazz, int areaid) {
	
		checkMd5(areaid, clazz);
		if (cache && areaCacheMap.containsKey(areaid)) {
			Map<Class, Map> map = areaCacheMap.get(areaid);
			if(map.containsKey(clazz)) {
				if(map.get(clazz) != null && map.get(clazz).size() != 0) {
					return map.get(clazz);					
				}
			}
		}

		checkMd5(0, clazz);
		Map<Class, Map> defaultCacheMap = getDefaultCacheMap();
//		if(!defaultCacheMap.containsKey(clazz)) {
//			String key = key(0, version, clazz.getSimpleName());
////			String key = String.format("ACT:DATA:" + 0 + ":%s:DATAS:%s", version, clazz.getSimpleName());
//			RMap<String, T> rmap = connection.client().getMap(key);
//			if(rmap != null && rmap.size() != 0) {
//				defaultCacheMap.put(clazz, rmap);
//			}
//		}
		
		return defaultCacheMap.get(clazz);
	}
	
	/**
	 * 加载对应区数据
	 * @param <T>
	 * @param version
	 * @param clazz
	 * @param areaid
	 * @return
	 */
	public <T> Map<String, T> initAreaData(String version, Class<T> clazz, int areaid) {
		String key = key(areaid, version, clazz.getSimpleName());
		
		RMap<String, T> rmap = connection.client().getMap(key);
//		HashMap<String, T> map = new HashMap<>(rmap);
//		if(map != null && map.size() != 0) {
//			if(areaCacheMap.containsKey(areaid)) {
//				areaCacheMap.get(areaid).put(clazz, map);
//			}else {
//				Map<Class, Map> datamap = new HashMap<Class, Map>();
//				datamap.put(clazz, map);		
//				areaCacheMap.put(areaid, datamap);
//			}			
//		}
//		return map;
		
		return initAreaData(version, clazz, areaid, rmap);
	}

	@SuppressWarnings("rawtypes")
	public <T> Map<String, T> initAreaData(String version, Class<T> clazz, int areaid, RMap<String, T> rmap) {
//		String key = key(areaid, version, clazz.getSimpleName());
		
//		RMap<String, T> rmap = connection.client().getMap(key);
		HashMap<String, T> map = new HashMap<>(rmap);
		if(map != null && map.size() != 0) {
			if(areaCacheMap.containsKey(areaid)) {
				areaCacheMap.get(areaid).put(clazz, map);
			}else {
				Map<Class, Map> datamap = new HashMap<Class, Map>();
				datamap.put(clazz, map);		
				areaCacheMap.put(areaid, datamap);
			}			
		}
		return map;
	}
	
	@SuppressWarnings("rawtypes")
	private <T> Map<String, T> initDefaultData(String version, Class<T> clazz) {
		String key = key(0, version, clazz.getSimpleName());
//		String key = String.format("ACT:DATA:" + areaid + ":%s:DATAS:%s", version, clazz.getSimpleName());
		
		if(getDefaultCacheMap() == null || getDefaultCacheMap().size() == 0) {
			Map<Class, Map> defaultCacheMap = new HashMap<Class, Map>();
			areaCacheMap.put(0, defaultCacheMap);
		}
		
		RMap<String, T> rmap = connection.client().getMap(key);
		HashMap<String, T> map = new HashMap<>(rmap);
		if(map != null && map.size() != 0) {
			getDefaultCacheMap().put(clazz, map);			
		}
		return map;
	}

	private void intMd5Data(ArrayList<Integer> areaids) {
		md5CacheMap.put(0, _getAllMD5(0, version));
		
		for(int areaid : areaids) {
//			int areaid = ab.getAreaId();
			RMap<String, String> rmap = _getAllMD5(areaid, version);
			if(rmap != null && rmap.size() != 0) {
				md5CacheMap.put(areaid, rmap);
			}
		}
	}
	
//	private <T> Map<String, T> getRedisData(int areaid, Class<T> clazz) {
//		String key = key(areaid, version, clazz.getSimpleName());
//		RMap<String, T> rmap = connection.client().getMap(key);
//		HashMap<String, T> map = new HashMap<>(rmap);
//		return map;
//	}
	
	synchronized static public <T> String getMD5(int areaid, Class<T> clazz) {
		return instance._getMD5(areaid, version, clazz);
	}

	private <T> String _getMD5(int areaid, String version, Class<T> clazz) {
		RMap<String, String> rmap = connection.client().getMap(md5key(areaid, version));
		String filename = String.format("%s.json", clazz.getSimpleName());
		return rmap.get(filename);
	}
	
	private <T> RMap<String, String> _getAllMD5(int areaid, String version) {
		RMap<String, String> rmap = connection.client().getMap(md5key(areaid, version));
		return rmap;
	}

	/** 缓存 */
	@SuppressWarnings("rawtypes")
	private Map<Integer, Map<Class, Map>> areaCacheMap = new HashMap<Integer, Map<Class,Map>>();	//key:areaid value:key:class value:表格数据

//	/** 默认缓存数据	 */
//	@SuppressWarnings("rawtypes")
//	private Map<Class, Map> defaultCacheMap = new HashMap<Class, Map>();	// 
	
	@SuppressWarnings("rawtypes")
	private Map<Class, Map> getDefaultCacheMap(){
		return areaCacheMap.get(0);
	}
	
	/** md5缓存数据	 */
	private Map<Integer, Map<String, String>> md5CacheMap = new HashMap<Integer, Map<String,String>>();

	private <T> void checkMd5(int areaid, Class<T> clazz) {
		String newmd5 = getMD5(areaid, clazz);
		
		String filename = String.format("%s.json", clazz.getSimpleName());
		Map<String, String> oldmd5Map = md5CacheMap.get(areaid);
		if(oldmd5Map == null || oldmd5Map.size() == 0) {
			if(newmd5 != null) {
				oldmd5Map = new HashMap<String, String>();
				initAreaData(version, clazz, areaid);
				oldmd5Map.put(filename, newmd5);
				md5CacheMap.put(areaid, oldmd5Map);
				return;
			}
			
			return;
		}
		
		String oldmd5 = oldmd5Map.get(filename);
		if(oldmd5 == null || oldmd5.equals("")) {
			if(newmd5 != null) {
				initAreaData(version, clazz, areaid);
				oldmd5Map.put(filename, newmd5);
				return;
			}
		}
		

		if(newmd5 != null && !newmd5.equals(oldmd5)) {
			initAreaData(version, clazz, areaid);
			oldmd5Map.put(filename, newmd5);
			return;
		}
	}
	
//	private String key(int areaid , String classname) {
//		return key(areaid , version, classname);
//	}
	
	private String key(int areaid , String version, String classname) {
		return String.format("ACT:DATA:" + areaid + ":%s:DATAS:%s", version, classname);
	}

//	private String md5key(int areaid) {
//		return md5key(areaid , version);
//	}
	
	private String md5key(int areaid , String version) {
		return String.format("ACT:DATA:%s:%s:MD5", areaid, version);
	}
}
